/**
 * @author guobingbing
 * @version 1.0
 * @wechat t_gbinb
 * @create 2021/5/21 15:24
 * =========================================================
 */

/**
 * 菜单树
 * @param rootPath
 * @param elementId
 * @constructor
 */
function MenuTree(rootPath, elementId) {
    this.rootPath = rootPath;
    this.tree = $('#' + elementId);
    this.tab = undefined;
    this.clickEvent = undefined;
    this.contextMenu = undefined;
    this.parentNode = undefined;
    this.dragTarget = undefined;
    this.copyNode = undefined;
    let that = this;
    this.tree.tree({
        onClick: function (node) {
            if(that.clickEvent!==undefined && typeof(that.clickEvent)==='function'){
                that.clickEvent(node);
            }
        },
        onContextMenu : function(e, node) {
            e.preventDefault();
            that.tree.tree('select', node.target);
            that.createContextMenu(e, node);
        },
        onStartDrag: function (node) {
            that.parentNode = that.tree.tree('getParent', node.target);
        },
        onDragEnter: function (target, source){
            that.dragTarget = target;
        },
        onStopDrag: function (node) {
            let parent = that.tree.tree('getParent', node.target);
            if(that.parentNode){
                if(that.parentNode.id!==parent.id){
                    let url = that.rootPath + '/auth/element/treeDrag';
                    let data = {
                        id: node.id,
                        parentId: parent.id
                    };
                    $.post(url, data, function (result) {
                        if(result.status!==1){
                            layer.alert('操作失败');
                            that.buildTree();
                        }
                    },'json');
                }else{
                    let targetNode = that.tree.tree('getNode', that.dragTarget);
                    if(targetNode){
                        let cmp = that.compareBeforeAfter(node, targetNode);
                        let newSort = cmp>0?(targetNode.sort + 1):(targetNode.sort - 1);
                        let data = {
                            "id":node.id,
                            "sort":newSort,
                            "moveId":targetNode.id,
                            "moveSort":targetNode.sort
                        };
                        let url = that.rootPath + '/auth/element/move';
                        $.post(url, data, function (result) {
                            if(result.status===0){
                                layer.alert(result.errorMsg);
                            }
                        },'json');
                    }
                }
            }
        }
    });
}

MenuTree.prototype.buildTree = function () {
    let that = this;
    $.get(that.rootPath + '/auth/common/getMenuTree', function (data) {
        that.tree.tree('loadData', data);
    });
};

MenuTree.prototype.getTree = function () {
    return this.tree;
};

MenuTree.prototype.addElement = function (category) {
    let that = this;
    let node = that.tree.tree('getSelected');
    let data = {
        "category": category,
        "planId": node.planId,
        "parentId": node.id
    };
    postJson(that.rootPath + '/auth/element/create', data, function (success, result) {
        if(success && result.status===1){
            let childNode = that.createChildNode(result.obj);
            that.tree.tree('append', {
                parent: node.target,
                data: [childNode]
            });
        }
    },'json');
};

MenuTree.prototype.createChildNode = function(element){
    let text = element.name;
    if(!element.enabled){
        text = "<span style='color:#aaa'>"+ text +"</span>";
    }
    let childNode = {
        id: element.id,
        text: text,
        category: element.category,
        planId: element.planId,
        parentId: element.parentId,
        sort: element.sort,
        url: element.category,
        enabled: element.enabled
    };
    return childNode;
};

MenuTree.prototype.delElement = function (callbackFunc) {
    let that = this;
    layerConfirm('确定要删除吗？',function(r) {
        if (r) {
            let lay = layerLoading();
            let node = that.tree.tree('getSelected');
            let data = {
                "id": node.id,
                "category": node.category
            };
            postJson(that.rootPath + '/auth/element/delete', data, function (success, result) {
                layer.close(lay);
                if(success){
                    //that.buildTree();
                    that.tree.tree('remove', node.target);
                    if(callbackFunc!==undefined){
                        callbackFunc(node);
                    }
                }
            },'json');
        }
    });
};

MenuTree.prototype.updateNodeText = function (newText) {
    let that = this;
    let node = that.tree.tree('getSelected');
    if (node){
        if(!node.enabled){
            newText = "<span style='color:#aaa'>"+ newText +"</span>";
        }
        that.tree.tree('update', {
            target: node.target,
            text: newText
        });
        let tab = that.tab.tabs('getSelected');
        if(tab){
            that.tab.tabs('update', {
                tab: tab,
                options: {
                    title: newText
                }
            });
        }
    }
};

MenuTree.prototype.compareBeforeAfter = function(node, targetNode){
    let that = this;
    let brothers = that.findBrotherNodes(node);
    if(brothers){
        let nodeIndex = 0;
        let targetIndex = 0;
        $.each(brothers, function (index, n) {
            if(node.id===n.id){
                nodeIndex = index;
            }else if(targetNode.id===n.id){
                targetIndex = index;
            }
        });
        return nodeIndex>targetIndex?1:-1;
    }else{
        return 0;
    }
};

MenuTree.prototype.findBrotherNodes = function(node){
    let nodeParent = this.tree.tree('getParent', node.target);
    let allChildren;
    if(nodeParent===null){
        allChildren = this.tree.tree('getRoots');
    }else{
        allChildren = this.tree.tree('getChildren', nodeParent.target);
    }
    let brothers = [];
    $.each(allChildren, function (index, child) {
        if(nodeParent===null){
            if(child.parentId==='0000'){
                brothers.push(child);
            }
        }else if(nodeParent.id===child.parentId){
            brothers.push(child);
        }
    });
    return brothers;
};

MenuTree.prototype.upOrDown = function (action) {
    let that = this;
    let node = that.tree.tree('getSelected');
    if(node){
        let brothers = that.findBrotherNodes(node);
        if(!brothers){
            return;
        }
        let beforeNode = undefined, afterNode = undefined;
        let broLen = brothers.length;
        for(let i=0; i<broLen; i++){
            if(node.id===brothers[i].id){
                if(i>0){
                    beforeNode = brothers[i-1];
                }
                if(i<(broLen-1)){
                    afterNode = brothers[i+1];
                }
                break;
            }
        }
        let url = that.rootPath + '/auth/element/move';
        let isRequest = false;
        let data = {};
        if(action==='up' && beforeNode){
            data = {
                "id":node.id,
                "sort":beforeNode.sort,
                "moveId":beforeNode.id,
                "moveSort":node.sort
            };
            isRequest = true;
        }else if(action==='down' && afterNode){
            data = {
                "id":node.id,
                "sort":afterNode.sort,
                "moveId":afterNode.id,
                "moveSort":node.sort
            };
            isRequest = true;
        }
        if(isRequest){
            $.post(url, data, function (result) {
                if(result.status===1){
                    that.tree.tree('remove', node.target);
                    if(action==='up'){
                        that.tree.tree('insert', {
                            before: beforeNode.target,
                            data: node
                        });
                    }else if(action==='down'){
                        that.tree.tree('insert', {
                            after: afterNode.target,
                            data: node
                        });
                    }
                }
            },'json');
        }
    }
};

MenuTree.prototype.modifySort = function(){
    let that = this;
    let node = this.tree.tree('getSelected');
    if(node){
        layer.prompt({title: '排序数字', formType: 3, value:node.sort}, function(val, index){
            let isMatch = /^[+]?[0-9]\d*$/.test(val);
            if(isMatch){
                node.sort = val;
                let url = that.rootPath + '/auth/element/modifySort';
                let data = {id:node.id, sort:val};
                let lay = layerLoading();
                $.post(url, data, function (result) {
                    layer.close(lay);
                    if(result.status===1){
                        layer.close(index);
                        let brothers = that.findBrotherNodes(node);
                        if(brothers){
                            let newBrothers = [];
                            $.each(brothers, function (index, bro) {
                                if(bro.id!==node.id){
                                    newBrothers.push(bro);
                                }
                            });
                            if(newBrothers.length<=0){
                                return;
                            }
                            let parentNode = that.tree.tree('getParent', node.target);
                            that.tree.tree('remove', node.target);
                            if(val>newBrothers.length){
                                if(parentNode){
                                    that.tree.tree('append',{
                                        parent: parentNode.target,
                                        data: [node]
                                    });
                                }else{
                                    that.tree.tree('append',{
                                        data: [node]
                                    });
                                }
                            }else if(val<=1){
                                that.tree.tree('insert',{
                                    before: newBrothers[0].target,
                                    data: [node]
                                });
                            }else{
                                that.tree.tree('insert',{
                                    before: newBrothers[val-1].target,
                                    data: [node]
                                });
                            }
                        }
                    }else{
                        layer.alert('修改出错！');
                    }
                },'json');

            }else{
                layer.alert('请输入正确的数字！');
            }
        });
    }
};

MenuTree.prototype.enabled = function (enabled) {
    let that = this;
    let node = that.tree.tree('getSelected');
    if(node){
        if(node.category==='testFragment'){
            if(enabled){
                layer.alert("测试片段无法启用！");
                return;
            }
        }
        let url = that.rootPath + '/auth/element/enabled';
        let data = {
            id: node.id,
            enabled: enabled
        };
        let lay = layerLoading(1);
        $.post(url, data, function (result) {
            layer.close(lay);
            if(result.status===1){
                //that.buildTree();
                let text = result.obj;
                if(!enabled){
                    text = "<span style='color:#aaa'>"+ text +"</span>";
                }
                node.enabled = enabled;
                that.updateNodeText(text);
            }
        },'json');
    }
};

MenuTree.prototype.createContextMenu = function (e, node) {
    let that = this;
    that.contextMenu.empty();
    let menus = baseMenus;
    if(mainMenuSet.has(node.category)){
        menus = mainMenus;
    }else if(testPlanSet.has(node.category)){
        menus = testPlanMenus;
    }else if(samplerSet.has(node.category)){
        menus = samplerMenus;
    }
    $.each(menus, function (index, m) {
        that.contextMenu.menu('appendItem', m);
        if(m.children){
            let parent = that.contextMenu.menu('findItem', m.text);
            $.each(m.children, function (index, c) {
                c.parent = parent.target;
                that.contextMenu.menu('appendItem', c);
            });
        }
    });
    //定位
    that.contextMenu.menu('show',{
        left: e.pageX,
        top: e.pageY
    });
};

MenuTree.prototype.copy = function () {
    let node = this.tree.tree('getSelected');
    if(node){
        this.copyNode = $.extend({}, node);
    }
};

MenuTree.prototype.paste = function () {
    let that = this;
    if(that.copyNode){
        let node = that.tree.tree('getSelected');
        if(node.id!==that.copyNode.id){
            let sort = 1;
            let before = '';
            let brothers = that.findBrotherNodes(node);
            if(brothers && brothers.length>0){
                sort = brothers[brothers.length-1].sort + 1;
                before = brothers[brothers.length-1].id;
            }
            let data = {
                id: that.copyNode.id,
                parentId: node.id,
                category: that.copyNode.category,
                planId: node.planId,
                sort: sort,
                moveId: before
            };
            let loading = layerLoading(1);
            $.post(that.rootPath + '/auth/element/paste', data, function (result) {
                layer.close(loading);
                if(result.status===1){
                    that.tree.tree('append', {
                        parent: node.target,
                        data: [result.obj]
                    });
                    that.copyNode = undefined;
                }
            },'json');
        }else{
            layer.alert('无法在同一节点下粘贴！');
        }
    }
};

MenuTree.prototype.recursionNode = function (parentNode, array) {
    let that = this;
    if(parentNode.children && parentNode.children.length>0){
        $.each(parentNode.children, function (index, child) {
            that.recursionNode(child, array);
            array.push(child.id + ':' + child.category);
        });
    }
};

/**
 * Tab对象
 * @param rootPath
 * @param elementId
 * @constructor
 */
function Tab(rootPath, elementId) {
    this.rootPath = rootPath;
    this.tab = $('#' + elementId);
    this.contextMenu = undefined;
    this.selectEvent = undefined;
    this.loadPanelEvent = undefined;
    let that = this;
    this.tab.tabs({
        onContextMenu : function(e, title, index) {
            e.preventDefault();
            that.tab.tabs('select', index);
            if(that.contextMenu!==undefined){
                that.contextMenu.menu('show', {
                    left : e.pageX,
                    top : e.pageY
                });
            }
        },
        onSelect: function(title, index){
            let tabPage = that.tab.tabs('getTab', index);
            let tabId = tabPage.panel('options').id;
            if(tabId){
                if(that.selectEvent!==undefined){
                    that.selectEvent(tabId);
                }
            }
        },
        onLoad: function (panel) {
            if(that.loadPanelEvent!==undefined){
                that.loadPanelEvent(panel);
            }
        }
    });
}

Tab.prototype.addPanel = function (node) {
    let that = this;
    let tabs = that.tab;
    let ttt = tabs.tabs('tabs');
    for(let i=0;i<ttt.length;i++){
        if(ttt[i].panel('options').id === node.category + '_'+node.id){
            if(!ttt[i].panel("options").disabled){
                ttt[i].panel("open");
            }
            return;
        }
    }

    tabs.tabs('add',{
        id: node.category + '_' + node.id,
        title: node.text,
        iconCls: node.iconCls,
        category: node.category,
        closable: true,
        href: node.url
    });
};

Tab.prototype.refreshTab = function () {
    let tabPage = this.tab.tabs('getSelected');
    tabPage.panel("refresh");
};

Tab.prototype.closeCurrentTab = function () {
    let tabPage = this.tab.tabs('getSelected');
    let index = this.tab.tabs('getTabIndex', tabPage);
    this.tab.tabs("close", index);
};

Tab.prototype.closeOtherTab = function () {
    let tabs = this.tab.tabs("tabs");
    let length = tabs.length;
    let tab = this.tab.tabs('getSelected');
    for (let i = 0; i < length; i++) {
        let lopTabId = tabs[i].panel('options').id;
        if(lopTabId!==tab.panel('options').id){
            let index = this.tab.tabs('getTabIndex', tabs[i]);
            this.tab.tabs("close", index);
        }
    }
};

Tab.prototype.closeAllTab = function () {
    let tabs = this.tab.tabs("tabs");
    let length = tabs.length;
    for (let i = 0; i < length; i++) {
        this.tab.tabs("close", 0);
    }
};

/**
 * 接收测试计划通知
 * @param remoteUrl websocket url
 * @constructor
 */
function TestResultNotice(remoteUrl) {
    this.host = location.host;
    this.wsProtocol = 'ws';
    this.protocol = document.location.protocol;
    if(this.protocol.indexOf('https')===0){
        this.wsProtocol = 'wss';
    }
    this.remoteUrl = remoteUrl;
    this.socket = undefined;
    this.messageEvent = undefined;
    this.resultEvent = [];
    this.aggregateReportEvent = undefined;
    this.interval = undefined;
}

TestResultNotice.prototype.connect = function () {
    let that = this;
    $.ajaxSettings.async = false;
    $.post(contextPath + '/getUserId', function (result) {
        if(result.status===1){
            that.socket = new WebSocket(that.wsProtocol + '://'+that.host+ that.remoteUrl + '/' + result.obj);
            that.socket.onopen = function () {
                console.log("连接建立成功...");
                if(!that.interval){
                    that.interval = setInterval(function () {
                        that.heart();
                    },10*1000);
                }
            };
            that.socket.onclose = function (e) {
                console.log("连接关闭...");
                console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean);
            };
            that.socket.onerror = function () {
                console.log("发生错误...");
            };
            that.socket.onmessage = function (e) {
                that.receive(e.data);
            };
        }else if(result.status===2){
            if(that.interval){
                clearInterval(that.interval);
            }
            location.href = contextPath + '/login';
        }else{
            console.log(result.errorMsg);
        }
    },'json');
    $.ajaxSettings.async = true;
};

TestResultNotice.prototype.heart = function(){
    let that = this;
    if(that.socket===undefined){
        that.connect();
    }else if(that.socket.readyState===1){
        that.socket.send(JSON.stringify({type:0,message:'Ping - ' + new Date().getMilliseconds()}));
    }else if(that.socket.readyState===2){
        that.socket.close(1006, 'closed');
        that.connect();
    }else if(that.socket.readyState===3){
        that.connect();
    }
};

TestResultNotice.prototype.receive = function (message) {
    let json = $.parseJSON(message);
    if(json.type===2){
        if(this.messageEvent!==undefined){
            this.messageEvent(json);
        }
        if(this.resultEvent.length>0){
            for(let i=0; i<this.resultEvent.length; i++){
                let event = this.resultEvent[i];
                event(json);
            }
        }
        if(this.aggregateReportEvent!==undefined){
            this.aggregateReportEvent(json);
        }
    }
};

/**
 * 测试结果树
 * @param rootPath
 * @param tree
 * @constructor
 */
function SamplerTree(rootPath) {
    this.rootPath = rootPath;
    this.clickEvent = undefined;
}

SamplerTree.prototype.buildTree = function(tree, planId, testId, threadId){
    let that = this;
    let params = {'planId':planId, 'testId':testId, 'threadId':threadId};
    postJson(that.rootPath + '/auth/test/result/getSampleTree', params, function (success, data) {
        if(success){
            tree.tree('loadData', data);
        }else{
            console.log(data);
        }
    });
    tree.tree({
        onClick: function (node) {
            if(that.clickEvent!==undefined){
                that.clickEvent(node);
            }
        }
    });
};

/**
 * 测试元素
 * @constructor
 */
function TestElement(rootPath) {
    this.rootPath = rootPath;
}

TestElement.prototype.saveElement = function (eid, formId, callbackFunc) {
    let that = this;
    let form = $('#' + formId + eid);
    let isValid = form.form('validate');
    if (isValid){
        let lay = layerLoading(1);
        let url = that.rootPath + '/auth/element/update';
        let data = form.serializeJSON();
        postJson(url, data, function (success, result) {
            layer.close(lay);
            if(success){
                if(result.status===1){
                    layerSlide('保存成功');
                }else{
                    layer.alert(result.errorMsg);
                }
                if(callbackFunc!==undefined){
                    callbackFunc(eid, result.status);
                }
            }else{
                layer.alert({result});
            }
        });
    }
};

/**
 * 项目对象
 * @constructor
 */
function Project(rootPath) {
    this.rootPath = rootPath;
}

Project.prototype.openMain = function (tabs) {
    let that = this;
    let ttt = tabs.tabs('tabs');
    for(let i=0;i<ttt.length;i++){
        if(ttt[i].panel('options').id === 'project_tab'){
            if(!ttt[i].panel("options").disabled){
                ttt[i].panel("open");
            }
            return;
        }
    }

    tabs.tabs('add',{
        id:'project_tab',
        title: '项目管理',
        href: that.rootPath + '/auth/project/main',
        closable: true
    });
};

/**
 * 报表对象
 * @param rootPath
 * @constructor
 */
function Report(rootPath) {
    this.rootPath = rootPath;
}

Report.prototype.showSampleResult = function(sample, eid) {
    let sampleResult = $('#sample_result_' + eid);
    sampleResult.empty();
    let sampleRequest = $('#sample_request_header_' + eid);
    sampleRequest.empty();
    let sampleResponse = $('#sample_response_' + eid);
    sampleResponse.empty();
    if(sample===undefined || sample.category===undefined){
        return;
    }

    let sb = new StringBuilder();
    if(sample.category.lastIndexOf('Assertion')>=0){
        sb.append("Assertion error：" + sample.assertionError + "<br/>");
        sb.append("Assertion failure：" + sample.assertionFailure + "<br/>");
        sb.append("Assertion failure message：" + sample.assertionMessage + "<br/>");
        sampleResult.html(sb.toString());
    }else{
        sb.append("threadName：" + sample.threadName + "<br/>");
        sb.append("startTime：" + sample.startTimeFmt + "<br/>");
        sb.append("endTime：" + sample.endTimeFmt + "<br/>");
        sb.append("connectTime：" + sample.connectTime + "<br/>");
        sb.append("latency：" + sample.latency + "<br/>");
        sb.append("elapsedTime：" + sample.elapsedTime + "<br/>");
        sb.append("sentBytes：" + sample.sentBytes + "<br/>");
        sb.append("headersSize：" + sample.headersSize + "<br/>");
        sb.append("responseCode：" + sample.responseCode + "<br/>");
        if(sample.dataType==='json'){
            sb.append("responseMessage：" + sample.responseMessage + "<br/>");
        }else{
            sb.append("responseMessage：" + sample.responseMessage.replaceAll('\n', '<br/>') + "<br/>");
        }
        sb.append("sampleCount：" + sample.sampleCount + "<br/>");
        sb.append("samplerData：" + sample.samplerData.replaceAll('\n', '<br/>') + "<br/>");
        sampleResult.html(sb.toString());

        sampleRequest.html(sample.requestHeaders.replaceAll('\n', '<br/>'));
        if(sample.dataType==='json'){
            sampleResponse.text(sample.responseData);
        }else{
            sampleResponse.html(sample.responseData.replaceAll('\n', '<br/>'));
        }
    }
};

Report.prototype.getAggregateReport = function (planId, testId) {
    let data = {
        planId: planId,
        testId: testId,
        rows: 0
    };
    let url = this.rootPath + "/auth/test/result/getAggReportList";
    $.post(url, data, function (result) {
        let dg = $('#dg_aggregateReport');
        dg.datagrid('loadData',{total:0,rows:[]});
        if(result.status===1){
            dg.datagrid('loadData', result.obj);
        }else{
            console.log(result.errorMsg);
        }
    },'json');
};